import UIKit
import SnapKit

public class CodeBlockView: UIView {
    public var style: CodeBlockStyle
    private let language: String?
    private let code: String
    private let maxHeight: CGFloat?
    
    public var showHeader: Bool = true {
        didSet {
            headerView.isHidden = !showHeader
            updateLayout()
        }
    }
    public var showLanguageLabel: Bool = true {
        didSet {
            languageLabel.isHidden = !showLanguageLabel
        }
    }
    public var showCopyButton: Bool = true {
        didSet {
            copyButton.isHidden = !showCopyButton
        }
    }
    public var languageDisplayName: String? {
        didSet {
            languageLabel.text = languageDisplayName?.lowercased() ?? language?.uppercased()
        }
    }
    public var copyButtonImage: UIImage? {
        didSet {
            copyButton.setImage(copyButtonImage ?? UIImage(systemName: "doc.on.doc"), for: .normal)
        }
    }
    public var copyButtonTitle: String? {
        didSet {
            copyButton.setTitle(copyButtonTitle, for: .normal)
        }
    }
    public var headerBackgroundColor: UIColor? {
        didSet {
            headerView.backgroundColor = headerBackgroundColor ?? style.headerBackgroundColor
        }
    }
    public var languageLabelFont: UIFont? {
        didSet {
            languageLabel.font = languageLabelFont ?? style.languageLabelFont
        }
    }
    public var languageLabelTextColor: UIColor? {
        didSet {
            languageLabel.textColor = languageLabelTextColor ?? style.languageLabelColor
        }
    }
    public var copyButtonTintColor: UIColor? {
        didSet {
            copyButton.tintColor = copyButtonTintColor ?? style.copyButtonTintColor
        }
    }
    public var onCopy: (() -> Void)?
    
    private let containerView = UIView()
    private let headerView = UIView()
    private let languageLabel = UILabel()
    private let copyButton = UIButton(type: .system)
    private let codeTextView = UITextView()
    private let expandButton = UIButton(type: .system)
    private let gradientMaskLayer = CAGradientLayer()
    private let themeButton = UIButton(type: .system)
    
    private var isExpanded = false
    private var originalHeight: CGFloat = 0
    private var heightConstraint: NSLayoutConstraint?
    private var codeTextViewTopConstraint: NSLayoutConstraint?
    private var currentTheme: CodeBlockStyle {
        didSet {
            style = currentTheme
            updateTheme()
        }
    }
    
    public init(style: CodeBlockStyle = .light, language: String? = nil, code: String, maxHeight: CGFloat? = nil) {
        self.style = style
        self.currentTheme = style
        self.language = language
        self.code = code
        self.maxHeight = maxHeight
        super.init(frame: .zero)
        setupViews()
        setupConstraints()
        configure()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupViews() {
        addSubview(containerView)
        containerView.addSubview(headerView)
        headerView.addSubview(languageLabel)
        headerView.addSubview(copyButton)
        containerView.addSubview(codeTextView)
        containerView.addSubview(expandButton)
        headerView.addSubview(themeButton)
        
        containerView.layer.cornerRadius = style.cornerRadius
        containerView.layer.borderWidth = style.borderWidth
        containerView.layer.borderColor = style.borderColor?.cgColor
        containerView.clipsToBounds = true
        
        headerView.backgroundColor = headerBackgroundColor ?? style.headerBackgroundColor
        headerView.isHidden = !showHeader
        
        languageLabel.font = languageLabelFont ?? style.languageLabelFont
        languageLabel.textColor = languageLabelTextColor ?? style.languageLabelColor
        languageLabel.isHidden = !showLanguageLabel
        
        copyButton.setImage(copyButtonImage ?? UIImage(systemName: "doc.on.doc"), for: .normal)
        copyButton.tintColor = copyButtonTintColor ?? style.copyButtonTintColor
        copyButton.addTarget(self, action: #selector(copyButtonTapped), for: .touchUpInside)
        copyButton.isHidden = !showCopyButton
        if let title = copyButtonTitle {
            copyButton.setTitle(title, for: .normal)
        }
        
        codeTextView.backgroundColor = style.backgroundColor
        codeTextView.font = style.font
        codeTextView.textColor = style.textColor
        codeTextView.isEditable = false
        codeTextView.isScrollEnabled = true
        codeTextView.showsHorizontalScrollIndicator = true
        codeTextView.showsVerticalScrollIndicator = true
        codeTextView.textContainerInset = style.codeTextInsets
        codeTextView.textContainer.lineFragmentPadding = 0
        
        expandButton.backgroundColor = style.expandButtonColor
        expandButton.setTitleColor(style.expandButtonTextColor, for: .normal)
        expandButton.titleLabel?.font = style.expandButtonFont
        expandButton.layer.cornerRadius = style.expandButtonCornerRadius
        expandButton.setTitle("Show more", for: .normal)
        expandButton.addTarget(self, action: #selector(expandButtonTapped), for: .touchUpInside)
        expandButton.isHidden = true
        expandButton.clipsToBounds = true
        expandButton.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
        
        gradientMaskLayer.colors = style.gradientMaskColors
        gradientMaskLayer.locations = style.gradientMaskLocations
        gradientMaskLayer.startPoint = CGPoint(x: 0.5, y: 0)
        gradientMaskLayer.endPoint = CGPoint(x: 0.5, y: 1)
        
        themeButton.setImage(UIImage(systemName: "paintpalette"), for: .normal)
        themeButton.tintColor = copyButtonTintColor ?? style.copyButtonTintColor
        themeButton.addTarget(self, action: #selector(themeButtonTapped), for: .touchUpInside)
    }
    
    private func setupConstraints() {
        // Container view constraints
        containerView.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(style.containerInsets)
        }
        
        // Header view constraints
        headerView.snp.makeConstraints { make in
            make.top.leading.trailing.equalTo(containerView)
            make.height.equalTo(showHeader ? style.headerHeight : 0)
        }
        
        // Language label constraints
        languageLabel.snp.makeConstraints { make in
            make.leading.equalTo(headerView).offset(style.languageLabelInsets.left)
            make.centerY.equalTo(headerView)
        }
        
        // Copy button constraints
        copyButton.snp.makeConstraints { make in
            make.trailing.equalTo(headerView).offset(-style.copyButtonInsets.right)
            make.centerY.equalTo(headerView)
            make.size.equalTo(style.copyButtonSize)
        }
        
        // Theme button constraints
        themeButton.snp.makeConstraints { make in
            make.trailing.equalTo(copyButton.snp.leading).offset(-8)
            make.centerY.equalTo(headerView)
            make.size.equalTo(style.copyButtonSize)
        }
        
        // Code text view constraints
        codeTextView.snp.makeConstraints { make in
            make.top.equalTo(showHeader ? headerView.snp.bottom : containerView.snp.top)
            make.leading.trailing.equalTo(containerView)
            make.bottom.equalTo(containerView).offset(-style.expandButtonHeight - 20)
        }
        
        // Expand button constraints
        expandButton.snp.makeConstraints { make in
            make.leading.trailing.equalTo(containerView).inset(12)
            make.bottom.equalTo(containerView).offset(-12)
            make.height.equalTo(0) // 初始高度为0，在需要时更新
        }
    }
    
    private func configure() {
        languageLabel.text = languageDisplayName?.uppercased() ?? language?.uppercased()
        
        // 设置代码文本
        let highlighter = SyntaxHighlighter(theme: style.syntaxTheme)
        let attributedCode = highlighter.highlight(code, language: language)
        codeTextView.attributedText = attributedCode
        
        // 让文本视图重新计算内容大小
        codeTextView.layoutIfNeeded()
        
        // 计算代码内容的实际高度
        let contentSize = codeTextView.sizeThatFits(
            CGSize(width: bounds.width - style.containerInsets.left - style.containerInsets.right,
                  height: .greatestFiniteMagnitude)
        )
        
        // 计算总内容高度（包括header和expandButton）
        let totalContentHeight = contentSize.height + 
            (showHeader ? style.headerHeight : 0) + 
            style.containerInsets.top + 
            style.containerInsets.bottom + 32 // 增加内边距
        
        if let maxHeight = maxHeight, totalContentHeight > maxHeight {
            // 内容超过最大高度时显示展开按钮
            expandButton.isHidden = false
            
            // 更新展开按钮约束
            expandButton.snp.updateConstraints { make in
                make.height.equalTo(style.expandButtonHeight)
            }
            
            // 更新代码文本视图约束
            codeTextView.snp.updateConstraints { make in
                make.bottom.equalTo(expandButton.snp.top).offset(-8)
            }
            
            // 更新容器高度
            containerView.snp.makeConstraints { make in
                heightConstraint = make.height.equalTo(maxHeight).constraint.layoutConstraints.first
            }
            
            // 设置渐变遮罩
            updateGradientMask()
            
            // 保存原始高度用于展开/收起
            originalHeight = totalContentHeight
        } else {
            // 内容未超过最大高度时隐藏展开按钮
            expandButton.isHidden = true
            
            // 更新展开按钮约束
            expandButton.snp.updateConstraints { make in
                make.height.equalTo(0)
            }
            
            // 更新代码文本视图约束
            codeTextView.snp.updateConstraints { make in
                make.bottom.equalTo(containerView).offset(0)
            }
            
            // 更新容器高度
            containerView.snp.makeConstraints { make in
                heightConstraint = make.height.equalTo(totalContentHeight).constraint.layoutConstraints.first
            }
            
            // 移除遮罩
            codeTextView.layer.mask = nil
        }
        
        // 强制布局更新
        setNeedsLayout()
        layoutIfNeeded()
    }
    
    private func updateGradientMask() {
        if !isExpanded && !expandButton.isHidden {
            let maskLayer = CAGradientLayer()
            maskLayer.frame = codeTextView.bounds
            maskLayer.colors = [
                UIColor.black.cgColor,
                UIColor.black.cgColor,
                UIColor.black.cgColor,
                UIColor.clear.cgColor
            ]
            maskLayer.locations = [0, 0.7, 0.85, 1.0]
            codeTextView.layer.mask = maskLayer
        } else {
            codeTextView.layer.mask = nil
        }
    }
    
    @objc private func copyButtonTapped() {
        UIPasteboard.general.string = code
        onCopy?()
        
        let originalImage = copyButton.imageView?.image
        copyButton.setImage(UIImage(systemName: "checkmark"), for: .normal)
        
        UIView.animate(withDuration: 0.3, animations: {
            self.copyButton.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
        }) { _ in
            UIView.animate(withDuration: 0.3) {
                self.copyButton.transform = .identity
            }
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
                self.copyButton.setImage(originalImage, for: .normal)
            }
        }
    }
    
    @objc private func expandButtonTapped() {
        guard let maxHeight = maxHeight else { return }
        
        isExpanded.toggle()
        
        // 更新按钮标题
        expandButton.setTitle(isExpanded ? "Show less" : "Show more", for: .normal)
        
        // 计算目标高度
        let targetHeight = isExpanded ? originalHeight : maxHeight
        
        // 更新高度约束
        heightConstraint?.constant = targetHeight
        
        // 执行动画
        UIView.animate(
            withDuration: 0.3,
            delay: 0,
            options: .curveEaseInOut,
            animations: {
                // 更新遮罩
                self.updateGradientMask()
                self.layoutIfNeeded()
            }
        )
    }
    
    @objc private func themeButtonTapped() {
        let alert = UIAlertController(title: "Select Theme", message: nil, preferredStyle: .actionSheet)
        
        let themes: [(name: String, theme: CodeBlockStyle)] = [
            ("Light", .light),
            ("Dark", .dark),
            ("GitHub", .github),
            ("One Dark", .oneDark),
            ("Solarized Light", .solarizedLight),
            ("Xcode", .xcode),
            ("Dracula", .dracula)
        ]
        
        for (name, theme) in themes {
            let action = UIAlertAction(title: name, style: .default) { [weak self] _ in
                self?.currentTheme = theme
            }
            alert.addAction(action)
        }
        
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        
        // For iPad support
        if let popover = alert.popoverPresentationController {
            popover.sourceView = themeButton
            popover.sourceRect = themeButton.bounds
        }
        
        if let viewController = findCodeViewController() {
            viewController.present(alert, animated: true)
        }
    }
    
    public func updateTheme() {
        // 更新视图样式
        containerView.layer.cornerRadius = style.cornerRadius
        containerView.layer.borderWidth = style.borderWidth
        containerView.layer.borderColor = style.borderColor?.cgColor
        
        // 更新 header 样式
        headerView.backgroundColor = style.headerBackgroundColor
        languageLabel.font = style.languageLabelFont
        languageLabel.textColor = style.languageLabelColor
        copyButton.tintColor = style.copyButtonTintColor
        themeButton.tintColor = style.copyButtonTintColor
        
        // 更新代码区域样式
        codeTextView.backgroundColor = style.backgroundColor
        codeTextView.font = style.font
        codeTextView.textColor = style.textColor
        codeTextView.textContainerInset = style.codeTextInsets
        
        // 更新展开按钮样式
        expandButton.backgroundColor = style.expandButtonColor
        expandButton.setTitleColor(style.expandButtonTextColor, for: .normal)
        expandButton.titleLabel?.font = style.expandButtonFont
        expandButton.layer.cornerRadius = style.expandButtonCornerRadius
        
        // 更新渐变遮罩
        gradientMaskLayer.colors = style.gradientMaskColors
        gradientMaskLayer.locations = style.gradientMaskLocations
        
        // 重新应用语法高亮
        let highlighter = SyntaxHighlighter(theme: style.syntaxTheme)
        let attributedCode = highlighter.highlight(code, language: language)
        codeTextView.attributedText = attributedCode
        
        // 更新布局
        setNeedsLayout()
        layoutIfNeeded()
    }
    
    // Helper method to find the view controller
    internal func findCodeViewController() -> UIViewController? {
        var responder: UIResponder? = self
        while let nextResponder = responder?.next {
            if let viewController = nextResponder as? UIViewController {
                return viewController
            }
            responder = nextResponder
        }
        return nil
    }
    
    private func updateLayout() {
        // 更新 header 高度
        headerView.snp.updateConstraints { make in
            make.height.equalTo(showHeader ? style.headerHeight : 0)
        }
        
        // 让文本视图重新计算内容大小
        codeTextView.layoutIfNeeded()
        
        // 计算新的内容高度
        let contentSize = codeTextView.sizeThatFits(
            CGSize(width: bounds.width - style.containerInsets.left - style.containerInsets.right,
                  height: .greatestFiniteMagnitude)
        )
        
        let totalContentHeight = contentSize.height + 
            (showHeader ? style.headerHeight : 0) + 
            (expandButton.isHidden ? 0 : style.expandButtonHeight) +
            style.containerInsets.top + 
            style.containerInsets.bottom + 24
        
        // 更新容器高度
        if let maxHeight = maxHeight {
            let targetHeight = isExpanded ? totalContentHeight : min(maxHeight, totalContentHeight)
            heightConstraint?.constant = targetHeight
        } else {
            heightConstraint?.constant = totalContentHeight
        }
        
        // 更新代码文本视图的约束
        if expandButton.isHidden {
            codeTextView.snp.updateConstraints { make in
                make.bottom.equalTo(containerView).offset(-12)
            }
        } else {
            codeTextView.snp.updateConstraints { make in
                make.bottom.equalTo(expandButton.snp.top).offset(-8)
            }
        }
        
        // 更新展开按钮的约束
        expandButton.snp.updateConstraints { make in
            make.height.equalTo(expandButton.isHidden ? 0 : style.expandButtonHeight)
        }
        
        // 更新渐变遮罩
        updateGradientMask()
        
        // 强制布局更新
        setNeedsLayout()
        layoutIfNeeded()
    }
    
    public override func layoutSubviews() {
        super.layoutSubviews()
        updateGradientMask()
    }
} 
